<script setup lang="ts">
import { ref, onMounted } from "vue"
import poprect from '../images/animate_snowball.webp'
import rhinoSrc from '../images/rhino.webp'
import parkSrc from '../images/park.webp'

const btnRef = ref(null)
const canvasRef = ref(null)
const popRef = ref(null)

const canvasImgRef = ref(null)

enum DemoType {
  DEFAULT = 'default',
  GETIMAGE = 'getImage',
  CLOCK = 'clock',
  DRAWIMAGE = 'drawImage'
}
const props = defineProps({
  demoName: {
    type: String,
    validator(value: string): boolean {
      return [DemoType.DEFAULT, DemoType.GETIMAGE, DemoType.CLOCK, DemoType.DRAWIMAGE].includes(value)
    },
    default: DemoType.DEFAULT
  }
})

const drawSnowBall = (canvasEl, btnE, popE) => {
  const popEl = popE
  const btnEl = btnE
  popEl.popover = "auto"
  btnEl.popoverTargetElement = popEl
  btnEl.popoverTargetAction = "toggle"

  const canvas = canvasEl
  const ctx = canvas.getContext('2d')

  let particles = []
  let tick = 0
  let isOpen = false
  function loop() {
    if(!isOpen) return
    requestAnimationFrame(loop)
    createParticles()
    updateParticles()
    killParticles()
    drawParticles()
  }

  const createParticles = () => {
    //check on every 10th tick check
    if(tick % 10 == 0) {
      //add particle if fewer than 100
      if(particles.length < 100) {
        particles.push({
          x: Math.random()*canvas.width, //between 0 and canvas width
          y: 0,
          speed: 2+Math.random()*3, //between 2 and 5
          radius: 5+Math.random()*5, //between 5 and 10
          color: "white",
        })
      }
    }
    if(particles.length >= 100) return
    tick++
  }

  const updateParticles = () => {
    for (const partArg of particles) {
      partArg.y += partArg.speed
    }
  }

  const killParticles = () => {
    for (const partArg of particles) {
      if(partArg.y > canvas.height) {
        partArg.y = 0
      }
    }
  }

  const drawParticles = () => {
    ctx.fillStyle = "black"
    ctx.fillRect(0,0,canvas.width,canvas.height)
    for (const partArg of particles) {
      ctx.beginPath()
      ctx.arc(partArg.x,partArg.y, partArg.radius, 0, Math.PI*2)
      ctx.closePath()
      ctx.fillStyle = partArg.color
      ctx.fill()
    }
  }

  popEl.addEventListener("beforetoggle", (event) => {
    if (event.newState === "open") {
      ctx.clearRect(0, 0, canvas.width, canvas.height)
      isOpen = true
      requestAnimationFrame(loop)
    } else {
      isOpen = false
      particles.splice(0)
    }
  })

}

const drawColor = () => {
  const canvas = canvasImgRef.value
  const ctx = canvas.getContext('2d', { willReadFrequently: true})

  const img = new Image()
  img.crossOrigin = "anonymous"
  img.src = rhinoSrc
  img.onload = function () {
    ctx.drawImage(img, 0, 0)
    img.style.display = "none"
  };
  const hoveredColor = document.getElementById("hovered-color")
  const selectedColor = document.getElementById("selected-color")

  function pick(event, destination) {
    const x = event.offsetX
    const y = event.offsetY
    const pixel = ctx.getImageData(x, y, 1, 1)
    const data = pixel.data

    const rgba = `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${data[3] / 255})`
    destination.style.background = rgba
    destination.textContent = rgba

    return rgba
  }

  canvas.addEventListener("mousemove", function (event) {
    pick(event, hoveredColor)
  })
  canvas.addEventListener("click", function (event) {
    pick(event, selectedColor)
  })
}

const drawClock = () => {
  function clock() {
    const now = new Date()
    const canvas = canvasImgRef.value
    const ctx = canvas.getContext('2d', { willReadFrequently: true})
    ctx.save()
    ctx.clearRect(0, 0, 150, 150)
    ctx.translate(75, 75)
    ctx.scale(0.4, 0.4)
    ctx.rotate(-Math.PI / 2)
    ctx.strokeStyle = "black"
    ctx.fillStyle = "white"
    ctx.lineWidth = 8
    ctx.lineCap = "round"

    // Hour marks
    ctx.save()
    Array.from({ length: 12 }).forEach(_ => {
      ctx.beginPath()
      ctx.rotate(Math.PI / 6)
      ctx.moveTo(100, 0)
      ctx.lineTo(120, 0)
      ctx.stroke()
    })
    ctx.restore()

    // Minute marks
    ctx.save()
    ctx.lineWidth = 5
    Array.from({ length: 60 }).forEach((_, index) => {
      if (index % 5 !== 0) {
        ctx.beginPath()
        ctx.moveTo(117, 0)
        ctx.lineTo(120, 0)
        ctx.stroke()
      }
      ctx.rotate(Math.PI / 30)
    })
    ctx.restore()

    const sec = now.getSeconds()
    const min = now.getMinutes()
    let hr = now.getHours()
    hr = hr >= 12 ? hr - 12 : hr

    ctx.fillStyle = "black"

    // write Hours
    ctx.save()
    ctx.rotate(
        hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) * sec,
    )
    ctx.lineWidth = 14
    ctx.beginPath()
    ctx.moveTo(-20, 0)
    ctx.lineTo(80, 0)
    ctx.stroke()
    ctx.restore()

    // write Minutes
    ctx.save()
    ctx.rotate((Math.PI / 30) * min + (Math.PI / 1800) * sec)
    ctx.lineWidth = 10
    ctx.beginPath()
    ctx.moveTo(-28, 0)
    ctx.lineTo(112, 0)
    ctx.stroke()
    ctx.restore()

    // Write seconds
    ctx.save()
    ctx.rotate((sec * Math.PI) / 30)
    ctx.strokeStyle = "#D40000"
    ctx.fillStyle = "#D40000"
    ctx.lineWidth = 6
    ctx.beginPath()
    ctx.moveTo(-30, 0)
    ctx.lineTo(83, 0)
    ctx.stroke()
    ctx.beginPath()
    ctx.arc(0, 0, 10, 0, Math.PI * 2, true)
    ctx.fill()
    ctx.beginPath()
    ctx.arc(95, 0, 10, 0, Math.PI * 2, true)
    ctx.stroke()
    ctx.fillStyle = "rgba(0,0,0,0)"
    ctx.arc(0, 0, 3, 0, Math.PI * 2, true)
    ctx.fill()
    ctx.restore()

    ctx.beginPath()
    ctx.lineWidth = 14
    ctx.strokeStyle = "#325FA2"
    ctx.arc(0, 0, 142, 0, Math.PI * 2, true)
    ctx.stroke()

    ctx.restore()

    window.requestAnimationFrame(clock)
  }

  window.requestAnimationFrame(clock)
}

const drawFullImage = () => {
  const img = new Image()

  img.src = parkSrc
  const CanvasXSize = 800
  const CanvasYSize = 200
  const speed = 30 // lower is faster
  const scale = 1.05
  const y = -4.5 // vertical offset

  // Main program

  const dx = 0.75
  let imgW
  let imgH
  let x = 0
  let clearX
  let clearY
  let ctx

  img.onload = function () {
    imgW = img.width * scale
    imgH = img.height * scale

    if (imgW > CanvasXSize) {
      // image larger than canvas
      x = CanvasXSize - imgW
    }
    if (imgW > CanvasXSize) {
      // image width larger than canvas
      clearX = imgW
    } else {
      clearX = CanvasXSize
    }
    if (imgH > CanvasYSize) {
      // image height larger than canvas
      clearY = imgH
    } else {
      clearY = CanvasYSize
    }

    // get canvas context
    ctx = canvasImgRef.value.getContext("2d")

    // set refresh rate
    return setInterval(draw, speed)
  }

  function draw() {
    ctx.clearRect(0, 0, clearX, clearY) // clear the canvas

    // if image is <= Canvas Size
    if (imgW <= CanvasXSize) {
      // reset, start from beginning
      if (x > CanvasXSize) {
        x = -imgW + x
      }
      // draw additional image1
      if (x > 0) {
        ctx.drawImage(img, -imgW + x, y, imgW, imgH)
      }
      // draw additional image2
      if (x - imgW > 0) {
        ctx.drawImage(img, -imgW * 2 + x, y, imgW, imgH)
      }
    }

    // image is > Canvas Size
    else {
      // reset, start from beginning
      if (x > CanvasXSize) {
        x = CanvasXSize - imgW
      }
      // draw aditional image
      if (x > CanvasXSize - imgW) {
        ctx.drawImage(img, x - imgW + 1, y, imgW, imgH)
      }
    }
    // draw image
    ctx.drawImage(img, x, y, imgW, imgH)
    // amount to move
    x += dx
  }
}

onMounted(() => {
  switch (props.demoName) {
    case DemoType.DEFAULT:
      drawSnowBall(canvasRef.value, btnRef.value, popRef.value)
      break
    case DemoType.GETIMAGE:
      drawColor()
      break
    case DemoType.CLOCK:
      drawClock()
      break
    case DemoType.DRAWIMAGE:
      drawFullImage()
      break
  }
})

</script>

<template>
  <div v-if="props.demoName === DemoType.DEFAULT">
    <button ref="btnRef"><img class="w-52 h-26" :src="poprect"/></button>
    <div ref="popRef">
      <canvas width="400" height="300" class="border border-black" ref="canvasRef"></canvas>
    </div>
  </div>
  <div v-else-if="props.demoName === DemoType.GETIMAGE" class="flex">
    <canvas width="400" height="300" ref="canvasImgRef"></canvas>
    <div class="flex flex-1 h-75">
      <div id="hovered-color" class="w-1/2 h-full flex items-center justify-center"></div>
      <div id="selected-color" class="w-1/2 h-full flex items-center justify-center"></div>
    </div>
  </div>
  <canvas v-else-if="props.demoName === DemoType.CLOCK" width="400" height="300" ref="canvasImgRef"></canvas>
  <div v-else-if="props.demoName === DemoType.DRAWIMAGE" class="overflow-auto h-56" >
    <canvas width="800" height="200" ref="canvasImgRef"></canvas>
  </div>
</template>

<style scoped lang="scss">

</style>